package com.bill99.rpc.container.tomcat;

import java.lang.reflect.Method;

import org.apache.catalina.Container;
import org.apache.catalina.Engine;
import org.apache.catalina.Server;
import org.apache.catalina.Service;
import org.apache.catalina.connector.Connector;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bill99.rpc.RpcException;

/**
 * @author sheng.zhang
 */
public class TomcatServer {

	private static final Logger logger = LoggerFactory
			.getLogger(TomcatServer.class);

	public final static String SERVER_FACTORY_CLASSNAME = "org.apache.catalina.ServerFactory";

	public final static String HTTP_11 = "HTTP/1.1";

	public final static String HTTP_10 = "HTTP/1.0";

	public final static String SERVICE_DEFAULT = "Catalina";

	public static int getPort() {
		try {
			Connector conn = getHttpConnector();
			return conn.getPort();
		} catch (RpcException e) {
			logger.warn("Failed to get server port");
			// logger.warn(e.getMessage());
		}
		return -1;
	}

	public static String getPath() {
		try {
			StandardContext sc = getStandardContext();
			return sc.getPath();
		} catch (RpcException e) {
			logger.warn("Failed to get server path");
			// logger.warn(e.getMessage(), e);
		}
		return null;
	}

	private static StandardContext getStandardContext() {
		Engine engine = getEngine();
		Container[] containers = engine.findChildren();
		for (Container container : containers) {
			Container[] children = container.findChildren();
			for (Container child : children) {
				if (child instanceof StandardContext) {
					return (StandardContext) child;
				}
			}
		}
		return null;
	}

	private static Class<?> getClass(String className) {
		// 获得线程上下文的类加载器 , 如果不行，通过ThreadGroup去获取所有线程，在从线程中获取ClassLoader
		ClassLoader loader = Thread.currentThread().getContextClassLoader();
		try {
			return loader.loadClass(className);
		} catch (ClassNotFoundException e) {
			throw new RpcException("Class not found " + className, e);
		}
	}

	private static Server getServer() {
		Class<?> serverFactoryClass = getClass(SERVER_FACTORY_CLASSNAME);
		Method method;
		try {
			method = serverFactoryClass.getMethod("getServer");
			return (Server) method.invoke(null);
		} catch (Throwable t) {
			throw new RpcException(t.getMessage(), t);
		}

	}

	private static Service getService() {
		Server server = getServer();
		Service[] services = server.findServices();
		if (services.length == 1) {
			return services[0];
		} else {
			for (Service service : services) {
				if (SERVICE_DEFAULT.equals(service.getName()))
					return service;
			}
		}
		throw new RpcException(RpcException.UNKNOWN_EXCEPTION,
				"Tomcat service is null");
	}

	private static Engine getEngine() {
		Service service = getService();
		StandardEngine engine = (StandardEngine) service.getContainer();
		return engine;
	}

	private static Connector getHttpConnector() {
		Service service = getService();
		Connector[] connectors = service.findConnectors();
		for (Connector connector : connectors) {
			String protocol = connector.getProtocol().trim().toUpperCase();
			if (HTTP_10.equals(protocol) || HTTP_11.equals(protocol)) {
				return connector;
			}
		}
		throw new RpcException(RpcException.UNKNOWN_EXCEPTION,
				"Tomcat connector is null");
	}

}
